package com.record.utils;


import org.apache.commons.math3.distribution.FDistribution;
import java.util.*;

public class LeveneTest {
    private double F;
    private double pValue;

    public LeveneTest(List<double[]> groups) {
        calculate(groups);
    }

    public double getF() {
        return F;
    }

    public double getPValue() {
        return pValue;
    }

    private void calculate(List<double[]> groups) {
        int k = groups.size();
        if (k < 2) throw new IllegalArgumentException("至少需要两组数据");

        // Step 1: 计算每组中位数
        List<Double> medians = new ArrayList<>();
        for (double[] g : groups) {
            double[] sorted = Arrays.copyOf(g, g.length);
            Arrays.sort(sorted);
            double median = (sorted.length % 2 == 0)
                    ? (sorted[sorted.length / 2 - 1] + sorted[sorted.length / 2]) / 2.0
                    : sorted[sorted.length / 2];
            medians.add(median);
        }

        // Step 2: 计算 Z_ij = |X_ij - M_i|
        List<double[]> Z = new ArrayList<>();
        List<Double> allZ = new ArrayList<>();
        for (int i = 0; i < k; i++) {
            double[] g = groups.get(i);
            double[] zi = new double[g.length];
            for (int j = 0; j < g.length; j++) {
                zi[j] = Math.abs(g[j] - medians.get(i));
                allZ.add(zi[j]);
            }
            Z.add(zi);
        }

        double grandMean = allZ.stream().mapToDouble(Double::doubleValue).average().orElse(0.0);

        // Step 3: 计算 SSA 与 SSE
        double SSA = 0.0;
        double SSE = 0.0;
        int N = allZ.size();

        for (int i = 0; i < k; i++) {
            double[] zi = Z.get(i);
            double meanZi = Arrays.stream(zi).average().orElse(0.0);
            SSA += zi.length * Math.pow(meanZi - grandMean, 2);
            for (double z : zi) {
                SSE += Math.pow(z - meanZi, 2);
            }
        }

        // Step 4: 计算 F 值
        F = (SSA / (k - 1)) / (SSE / (N - k));

        // Step 5: 计算 p 值
        FDistribution fDist = new FDistribution(k - 1, N - k);
        pValue = 1 - fDist.cumulativeProbability(F);
    }
}
